/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <array>
#include <gtest/gtest.h>
#include <hilog/log.h>
#include <cmath>

#include "color.h"
#include "color_space.h"
#include "color_space_convertor.h"

using namespace testing::ext;

namespace OHOS {
namespace ColorManager {
constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, 0, "ColorManagerTest"};
#define __CLOG(func, fmt, ...) \
    func(LABEL, "%{public}s: " fmt , __func__, ##__VA_ARGS__)

#define CLOGFD(fmt, ...) __CLOG(::OHOS::HiviewDFX::HiLog::Debug, fmt, ##__VA_ARGS__)
#define CLOGFI(fmt, ...) __CLOG(::OHOS::HiviewDFX::HiLog::Info, fmt, ##__VA_ARGS__)
#define CLOGFW(fmt, ...) __CLOG(::OHOS::HiviewDFX::HiLog::Warn, fmt, ##__VA_ARGS__)
#define CLOGFE(fmt, ...) __CLOG(::OHOS::HiviewDFX::HiLog::Error, fmt, ##__VA_ARGS__)

class ColorManagerTest : public testing::Test {
public:
    static void SetUpTestCase() {};
    static void TearDownTestCase() {};

    const Color srgbColor_ = Color(0.1, 0.2, 0.3, 0.4);
};

inline void PrintLogSkMatrix3x3(const skcms_Matrix3x3& mx)
{
    CLOGFI("ColorManagerTest::PrintLogSkMatrix3x3");
    for (int i = 0; i < DIMES_3; ++i) {
        CLOGFI("[%{public}f %{public}f %{public}f]", mx.vals[i][0], mx.vals[i][1], mx.vals[i][2]);
    }
}

inline void PrintLogMatrix3x3(const Matrix3x3& vals)
{
    CLOGFI("ColorManagerTest::PrintLogMatrix3x3");
    for (int i = 0; i < DIMES_3; ++i) {
        CLOGFI("[%{public}f %{public}f %{public}f]", vals[i][0], vals[i][1], vals[i][2]);
    }
}

inline void PrintLogColor(const Color& vals)
{
    CLOGFI("ColorManagerTest::PrintLogColor");
    CLOGFI("type = [%{public}d]", vals.srcName);
    CLOGFI("rgba = [%{public}f %{public}f %{public}f %{public}f]", vals.r, vals.g, vals.b, vals.a);
}

inline void PrintLogColorDiff(const Color& src, const Color& dst)
{
    CLOGFI("ColorManagerTest::PrintLogColorDiff");
    CLOGFI("type = src[%{public}d] dst[%{public}d]", src.srcName, dst.srcName);
    CLOGFI("rgba diff = [%{public}f %{public}f %{public}f %{public}f]", fabs(src.r - dst.r), fabs(src.g - dst.g),
        fabs(src.b - dst.b), fabs(src.a - dst.a));
}

/*
* Function: ColorManagerTest
* Type: Function
* Rank: Important(2)
* EnvConditions: N/A
* CaseDescription: sRGB convert to sRGB
*/
HWTEST_F(ColorManagerTest, sRGBTosRGB, Function | SmallTest | Level2)
{
    Color result = srgbColor_.Convert(ColorSpaceName::SRGB);
    ASSERT_EQ(srgbColor_.ColorEqual(result), true);
}

/*
* Function: ColorManagerTest
* Type: Function
* Rank: Important(2)
* EnvConditions: N/A
* CaseDescription: interconversion between sRGB and Display_P3
*/
HWTEST_F(ColorManagerTest, sRGBToDisplay_P3, Function | SmallTest | Level2)
{
    Color result = srgbColor_.Convert(ColorSpace(ColorSpaceName::DISPLAY_P3));
    Color displayColor = Color(0.1238f, 0.19752f, 0.29182f, 0.4, ColorSpaceName::DISPLAY_P3);
    ASSERT_EQ(displayColor.ColorEqual(result), true);
    result = displayColor.Convert(ColorSpace(ColorSpaceName::SRGB));
    ASSERT_EQ(srgbColor_.ColorEqual(result), true);
}

/*
* Function: ColorManagerTest
* Type: Function
* Rank: Important(2)
* EnvConditions: N/A
* CaseDescription: interconversion between sRGB and Adobe
*/
HWTEST_F(ColorManagerTest, sRGBToAdobe, Function | SmallTest | Level2)
{
    Color result = srgbColor_.Convert(ColorSpace(ColorSpaceName::ADOBE_RGB));
    Color adobeColor = Color(0.15511f, 0.21232f, 0.3015f, 0.4, ColorSpaceName::ADOBE_RGB);
    ASSERT_EQ(adobeColor.ColorEqual(result), true);
    result = adobeColor.Convert(ColorSpace(ColorSpaceName::SRGB));
    ASSERT_EQ(srgbColor_.ColorEqual(result), true);
}

/*
* Function: ColorManagerTest
* Type: Function
* Rank: Important(2)
* EnvConditions: N/A
* CaseDescription: interconversion between sRGB and DCI_P3
*/
HWTEST_F(ColorManagerTest, sRGBToDCI_P3, Function | SmallTest | Level2)
{
    Color result = srgbColor_.Convert(ColorSpace(ColorSpaceName::DCI_P3));
    Color dciColor = Color(0.18801f, 0.26705f, 0.35889f, 0.4, ColorSpaceName::DCI_P3);
    ASSERT_EQ(dciColor.ColorEqual(result), true);
    result = dciColor.Convert(ColorSpace(ColorSpaceName::SRGB));
    ASSERT_EQ(srgbColor_.ColorEqual(result), true);
}

/*
* Function: ColorManagerTest
* Type: Function
* Rank: Important(2)
* EnvConditions: N/A
* CaseDescription: DCI_P3 convert to Display_P3
*/
HWTEST_F(ColorManagerTest, DCI_P3ToDisplay_P3, Function | SmallTest | Level2)
{
    Color dciColor = Color(0.1, 0.2, 0.3, 0.4, ColorSpaceName::DCI_P3);
    Color result = dciColor.Convert(ColorSpaceName::DISPLAY_P3);
    Color displayColor = Color(0.0421f, 0.12966f, 0.23048f, 0.4, ColorSpaceName::DISPLAY_P3);
    ASSERT_EQ(displayColor.ColorEqual(result), true);
}

/*
* Function: ColorManagerTest
* Type: Function
* Rank: Important(2)
* EnvConditions: N/A
* CaseDescription: Display_P3 convert to DCI_P3
*/
HWTEST_F(ColorManagerTest, Display_P3ToDCI_P3, Function | SmallTest | Level2)
{
    Color displayColor = Color(0.1, 0.2, 0.3, 0.4, ColorSpaceName::DISPLAY_P3);
    Color result = displayColor.Convert(ColorSpaceName::DCI_P3);
    Color dciColor = Color(0.16016f, 0.26943f, 0.36672f, 0.4, ColorSpaceName::DCI_P3);
    ASSERT_EQ(dciColor.ColorEqual(result), true);
}

/*
* Function: ColorManagerTest
* Type: Function
* Rank: Important(2)
* EnvConditions: N/A
* CaseDescription: ADOBE_RGB convert to DISPLAY_P3
*/
HWTEST_F(ColorManagerTest, AdobeToDisplay_P3, Function | SmallTest | Level2)
{
    Color adobeColor = Color(0.1, 0.2, 0.3, 0.4, ColorSpaceName::ADOBE_RGB);
    Color result = adobeColor.Convert(ColorSpaceName::DISPLAY_P3);
    Color displayColor = Color(0.03763f, 0.18272f, 0.28952f, 0.4, ColorSpaceName::DISPLAY_P3);
    ASSERT_EQ(displayColor.ColorEqual(result), true);
}

/*
* Function: ColorManagerTest
* Type: Function
* Rank: Important(2)
* EnvConditions: N/A
* CaseDescription: DISPLAY_P3 convert to ADOBE_RGB
*/
HWTEST_F(ColorManagerTest, Display_P3ToAdobe, Function | SmallTest | Level2)
{
    Color displayColor = Color(0.1, 0.2, 0.3, 0.4, ColorSpaceName::DISPLAY_P3);
    Color result = displayColor.Convert(ColorSpaceName::ADOBE_RGB);
    Color adobeColor = Color(0.13959f, 0.21513f, 0.30952f, 0.4, ColorSpaceName::ADOBE_RGB);
    ASSERT_EQ(adobeColor.ColorEqual(result), true);
}

/*
* Function: ColorManagerTest
* Type: Function
* Rank: Important(2)
* EnvConditions: N/A
* CaseDescription: Use Convertor to interconvert Display_P3 and Adobe
*/
HWTEST_F(ColorManagerTest, convertor_Display_P3ToAdobe, Function | SmallTest | Level2)
{
    auto convertor = ColorSpaceConvertor(ColorSpace(ColorSpaceName::DISPLAY_P3), ColorSpace(ColorSpaceName::ADOBE_RGB),
        GamutMappingMode::GAMUT_MAP_CONSTANT);
    std::array<float, 3> rgb = {0.1, 0.2, 0.3};
    Color displayColor = Color(rgb[0], rgb[1], rgb[2], 1.0, ColorSpaceName::DISPLAY_P3);
    auto res = convertor.Convert(rgb);
    Color result = Color(res[0], res[1], res[2], 1.0, ColorSpaceName::ADOBE_RGB);
    Color adobeColor = Color(0.13959f, 0.21513f, 0.30952f, 1.0, ColorSpaceName::ADOBE_RGB);
    ASSERT_EQ(adobeColor.ColorEqual(result), true);
    // convert adobeColor to displayColor
    convertor = ColorSpaceConvertor(ColorSpace(ColorSpaceName::ADOBE_RGB), ColorSpace(ColorSpaceName::DISPLAY_P3),
        GamutMappingMode::GAMUT_MAP_CONSTANT);
    res = convertor.Convert(res);
    result = Color(res[0], res[1], res[2], 1.0, ColorSpaceName::DISPLAY_P3);
    ASSERT_EQ(displayColor.ColorEqual(result), true);
}

/*
* Function: ColorManagerTest
* Type: Function
* Rank: Important(2)
* EnvConditions: N/A
* CaseDescription: sRGB convert to DCI_P3
*/
HWTEST_F(ColorManagerTest, skiaToColorSpace, Function | SmallTest | Level2)
{
    sk_sp<SkColorSpace> skiaSrgb = SkColorSpace::MakeSRGB();
    ASSERT_NE(nullptr, skiaSrgb);
    Color color = Color(0.1, 0.2, 0.3, 0.4);
    ColorSpace srgb = ColorSpace(skiaSrgb);
    Color result = color.Convert(srgb);
    ASSERT_EQ(color.ColorEqual(result), true);

    sk_sp<SkColorSpace> skiaP3 = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
    ASSERT_NE(nullptr, skiaP3);
    ColorSpace displayP3 = ColorSpace(skiaP3);
    result = color.Convert(displayP3);
    Color p3Color = Color(0.1238f, 0.19752f, 0.29182f, 0.4, ColorSpaceName::DISPLAY_P3);
    ASSERT_EQ(p3Color.ColorEqual(result), true);
}
}
}